package org.jetlinks.pro.device;

import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
import org.hswebframework.web.authorization.token.DefaultUserTokenManager;
import org.hswebframework.web.authorization.token.UserTokenManager;
import org.hswebframework.web.starter.jackson.CustomCodecsAutoConfiguration;
import org.jetlinks.core.ProtocolSupport;
import org.jetlinks.core.ProtocolSupports;
import org.jetlinks.core.cluster.ClusterManager;
import org.jetlinks.core.device.DeviceRegistry;
import org.jetlinks.core.event.EventBus;
import org.jetlinks.core.server.monitor.GatewayServerMetrics;
import org.jetlinks.core.server.monitor.GatewayServerMonitor;
import org.jetlinks.pro.gateway.session.DefaultDeviceSessionManager;
import org.jetlinks.pro.gateway.session.entity.PersistentSessionEntity;
import org.jetlinks.pro.protocol.SpringServiceContext;
import org.jetlinks.supports.cluster.EventBusDeviceOperationBroker;
import org.jetlinks.supports.cluster.redis.RedisClusterManager;
import org.jetlinks.supports.event.BrokerEventBus;
import org.jetlinks.supports.official.JetLinksDeviceMetadataCodec;
import org.jetlinks.supports.protocol.management.ClusterProtocolSupportManager;
import org.jetlinks.supports.server.monitor.MicrometerGatewayServerMetrics;
import org.jetlinks.supports.test.InMemoryDeviceRegistry;
import org.jetlinks.supports.test.MockProtocolSupport;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;

@Configuration
@ImportAutoConfiguration({
    CodecsAutoConfiguration.class,
    JacksonAutoConfiguration.class,
    CustomCodecsAutoConfiguration.class
})
public class DeviceTestConfiguration {


    @Bean
    @Primary
    public ProtocolSupports protocolSupports(){
        return new MockProtocolSupport();
    }

    @Bean
    public DeviceRegistry deviceRegistry(){
        return new InMemoryDeviceRegistry();
    }

    @Bean(initMethod = "startup",destroyMethod = "shutdown")
    public RedisClusterManager clusterManager(ReactiveRedisTemplate<Object,Object> template){
        return new RedisClusterManager("test","test",template);
    }

    @Bean
    public EventBus eventBus(){
        return new BrokerEventBus();
    }

    @Bean
    public ClusterProtocolSupportManager clusterProtocolSupportManager(ClusterManager clusterManager){
        return new ClusterProtocolSupportManager(clusterManager);
    }

    @Bean
    public SpringServiceContext springServiceContext(ApplicationContext context){
        return new SpringServiceContext(context);
    }

    @Bean
    public Scheduler scheduler(){
        return Schedulers.parallel();
    }

    @Bean(initMethod = "start", destroyMethod = "dispose")
    public EventBusDeviceOperationBroker clusterDeviceOperationBroker(ClusterManager clusterManager, EventBus eventBus) {
        return new EventBusDeviceOperationBroker(clusterManager.getCurrentServerId(), eventBus);
    }

    @Bean
    public UserTokenManager userTokenManager(){
        return new DefaultUserTokenManager();
    }

    @Bean(initMethod = "init", destroyMethod = "shutdown")
    public DefaultDeviceSessionManager deviceSessionManager(ReactiveRepository<PersistentSessionEntity, String> repository,
                                                            DeviceRegistry registry) {
        DefaultDeviceSessionManager sessionManager = new DefaultDeviceSessionManager();
        sessionManager.setGatewayServerMonitor(new GatewayServerMonitor() {
            @Override
            public String getCurrentServerId() {
                return "test";
            }

            @Override
            public GatewayServerMetrics metrics() {
                return new MicrometerGatewayServerMetrics("test");
            }
        });
        sessionManager.setRegistry(registry);
        sessionManager.setSessionRepository(repository);

        return sessionManager;
    }

    @Bean
    public JetLinksDeviceMetadataCodec jetLinksDeviceMetadataCodec(){
        return new JetLinksDeviceMetadataCodec();
    }

}
